Build lib tests and libraries in parallel
authorAlex Crichton <alex@alexcrichton.com>
Wed, 5 Nov 2014 03:40:06 +0000 (19:40 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Wed, 5 Nov 2014 21:40:31 +0000 (13:40 -0800)
When building unit tests for a library, we don't need the library itself to be
built beforehand, so the two can be built in parallel. If the crate takes awhile
to compile, this shows some excellent wall-time speedups.

src/cargo/ops/cargo_rustc/job_queue.rs
src/cargo/ops/cargo_rustc/mod.rs

index 86d8b9982beaa117e0478841d1058aff84c68225..554b3ca2f0586c5cf3b7ebe9409400cdd8c1385e 100644 (file)
@@ -53,7 +53,8 @@ pub enum TargetStage {
     StageRunCustomBuild,
     StageLibraries,
     StageBinaries,
-    StageTests,
+    StageLibraryTests,
+    StageBinaryTests,
 }
 
 type Message = (PackageId, TargetStage, Freshness, CargoResult<()>);
@@ -284,13 +285,17 @@ impl<'a> Dependency<(&'a Resolve, &'a PackageSet)>
             // do not depend on dev-dependencies.
             StageBinaries => vec![(id, StageLibraries)],
 
-            // Tests depend on all non-transitive dependencies
-            // (dev-dependencies) in addition to the library stage for this
-            // package.
-            StageTests => {
-                let mut base = vec![(id, StageLibraries)];
-                base.extend(deps.filter(|&(_, dep)| !dep.is_transitive())
-                                .map(|(id, _)| (id, StageLibraries)));
+            // Tests depend on all dependencies (including dev-dependencies) in
+            // addition to the library stage for this package. Note, however,
+            // that library tests only need to depend the custom build command
+            // being run, not the libraries themselves.
+            StageBinaryTests | StageLibraryTests => {
+                let mut base = if stage == StageBinaryTests {
+                    vec![(id, StageLibraries)]
+                } else {
+                    vec![(id, StageRunCustomBuild)]
+                };
+                base.extend(deps.map(|(id, _)| (id, StageLibraries)));
                 base
             }
         }
index 647fb0e6f41ebb83e495632a57cb3985d2026854..9b2c3bf78406b3204b629b1b9fcc32af35d8bbe0 100644 (file)
@@ -166,7 +166,8 @@ fn compile<'a, 'b>(targets: &[&'a Target], pkg: &'a Package,
     //
     // Each target has its own concept of freshness to ensure incremental
     // rebuilds on the *target* granularity, not the *package* granularity.
-    let (mut libs, mut bins, mut tests) = (Vec::new(), Vec::new(), Vec::new());
+    let (mut libs, mut bins, mut lib_tests, mut bin_tests) =
+            (Vec::new(), Vec::new(), Vec::new(), Vec::new());
     let (mut build_custom, mut run_custom) = (Vec::new(), Vec::new());
     for &target in targets.iter() {
         if target.get_profile().is_custom_build() {
@@ -193,9 +194,10 @@ fn compile<'a, 'b>(targets: &[&'a Target], pkg: &'a Package,
                          target.get_profile().is_test(),
                          target.get_profile().is_custom_build()) {
             (_, _, true) => &mut build_custom,
-            (_, true, _) => &mut tests,
-            (true, _, _) => &mut libs,
-            (false, false, _) if target.get_profile().get_env() == "test" => &mut tests,
+            (true, true, _) => &mut lib_tests,
+            (false, true, _) => &mut bin_tests,
+            (true, false, _) => &mut libs,
+            (false, false, _) if target.get_profile().get_env() == "test" => &mut bin_tests,
             (false, false, _) => &mut bins,
         };
         for (work, kind) in work.into_iter() {
@@ -244,7 +246,8 @@ fn compile<'a, 'b>(targets: &[&'a Target], pkg: &'a Package,
 
     jobs.enqueue(pkg, jq::StageLibraries, libs);
     jobs.enqueue(pkg, jq::StageBinaries, bins);
-    jobs.enqueue(pkg, jq::StageTests, tests);
+    jobs.enqueue(pkg, jq::StageBinaryTests, bin_tests);
+    jobs.enqueue(pkg, jq::StageLibraryTests, lib_tests);
     Ok(())
 }